package orz.mikeneck.server.locrec.model;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import orz.mikeneck.server.locrec.persistent.GpsRecord;
import orz.mikeneck.server.locrec.persistent.utils.PersistenceManagerUtil;

public class LocRecGpsModelImpl implements LocRecGpsModel {

	private PersistenceManager manager;

	private String loginId;

	private double longitude;

	private double latitude;

	private List<String> filter;

	private List<String> params;

	private long from = -1;

	private long to = -1;

	public LocRecGpsModelImpl(){
		persistentManagerIs(PersistenceManagerUtil.getManager());
		this.filter = new ArrayList<String>();
		this.params = new ArrayList<String>();
	}

	@Override
	public LocRecGpsModel addFilter(String condition){
		filter.add(condition);
		return this;
	}

	@Override
	public LocRecGpsModel and(){
		if(filter.size() > 0){
			filter.add(FILTER_SEPT_AND);
		}
		return this;
	}

	@Override
	public LocRecGpsModel or(){
		if(filter.size() > 0){
			filter.add(FILTER_SEPT_OR);
		}
		return this;
	}

	private String createFilter(){
		if(filter.size() == 0){
			return DEFAULT_FILTER;
		}
		StringBuilder sb = new StringBuilder();
		for(String item : filter){
			sb.append(item);
		}
		return sb.toString();
	}

	@Override
	public LocRecGpsModel addParameter(String param){
		if(params.size() > 0){
			params.add(PARAM_SEPARATER);
		}
		params.add(param);
		return this;
	}

	private String createParam(){
		if(params.size() == 0){
			return PARAM_LOGIN_ID;
		}
		StringBuilder sb = new StringBuilder();
		for(String item : params){
			sb.append(item);
		}
		return sb.toString();
	}

	@Override
	public LocRecGpsModel latitudeIs(double lat) throws NumberFormatException {
		if(isGpsInRange(lat, -90, 90)){
			this.latitude = lat;
			return this;
		}else{
			throw new NumberFormatException();
		}
	}

	@Override
	public LocRecGpsModel longitudeIs(double lon) throws NumberFormatException {
		if(isGpsInRange(lon, 0, 360)){
			this.longitude = lon;
			return this;
		}else{
			throw new NumberFormatException();
		}
	}

	@Override
	public LocRecGpsModel loginIdIs(String login) {
		this.loginId = login;
		return this;
	}

	@Override
	public LocRecGpsModel persistentManagerIs(PersistenceManager manager) {
		this.manager = manager;
		return this;
	}

	private boolean isGpsInRange(double value, double from, double to){
		return from <= value && to >= value;
	}

	@Override
	public void makePersistence() {
		Date createdAt = new Date();
		GpsRecord gps = new GpsRecord(loginId, latitude, longitude, createdAt);
		try{
			manager.makePersistent(gps);
		}finally{
			manager.close();
		}
	}

	@Override
	public void deletePersistence(){
		List<GpsRecord> result = findRecordByLoginId();
		manager.deletePersistentAll(result);
	}

	@Override
	public List<GpsRecord> findRecordByLoginId() {
		Query query = createQuery();
		@SuppressWarnings("unchecked")
		List<GpsRecord> result = (List<GpsRecord>) query.execute(loginId);
		return result;
	}

	@Override
	public List<GpsRecord> findRecordsWithParams(Object...params){
		Query query = createQuery();
		@SuppressWarnings("unchecked")
		List<GpsRecord> results = (List<GpsRecord>) query.executeWithArray(params);
		return results;
	}

	@Override
	public LocRecGpsModel recordsFrom(long from){
		this.from = from;
		return this;
	}

	@Override
	public LocRecGpsModel recordsTo(long to){
		this.to = to;
		return this;
	}

	@Override
	public Query createQuery() {
		Query query = manager.newQuery(GpsRecord.class);
		query.setFilter(createFilter());
		query.declareParameters(createParam());
		if(from > -1 && to > -1){
			query.setRange(from, to);
		}
		return query;
	}

	@Override
	public LocRecGpsModel userLocationIs(double lat, double lon)
			throws NumberFormatException {
		latitudeIs(lat);
		longitudeIs(lon);
		return this;
	}

}
